//
// Created by cxh19 on 2023/5/11.
//

#include "Texture.h"
#include "VkHelper.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

bool CTexture::load(VkPhysicalDeviceMemoryProperties physicalMemoType, VkPhysicalDeviceLimits physicalDevLimits, VkDevice device, VkCommandPool cmdPool, VkQueue queue, const char *fileName) {
    stbi_uc *pixels = stbi_load(fileName, &width, &height, &channels, STBI_rgb_alpha);
    if(nullptr == pixels){
        std::string msg("can not load the texture, fileName=");
        msg += fileName;
        throw std::runtime_error(msg);
    }

    VkDeviceSize size = width * width * 4;//rgba
    VkBuffer stagingBuffer;
    VkDeviceMemory stagingMemory;
    VkHelper::createBufferInternal(physicalMemoType, device, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
                                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
                                   size, &stagingBuffer, &stagingMemory);
    void* data;
    vkMapMemory(device, stagingMemory, 0, size, 0, &data);
    memcpy(data, pixels, static_cast<size_t>(size));
    vkUnmapMemory(device, stagingMemory);

    stbi_image_free(pixels);

    VkHelper::createImage(physicalMemoType, device, width, height, 1, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_SRGB,
                          VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
                          &textureImage, &textureImageMemory);
    VkHelper::transitionImageLayout(device, cmdPool, queue, textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
    VkHelper::transitionImageLayout(device, cmdPool, queue, textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                                    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
    VkHelper::copyBufferToImage(device, cmdPool, queue, stagingBuffer, textureImage, width, height);

    vkDestroyBuffer(device, stagingBuffer, VK_ALLOC);
    vkFreeMemory(device, stagingMemory, VK_ALLOC);

    //image view
    VkHelper::createImageView(device, textureImage, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, &imageView);

    //sampler
    VkHelper::createImageSampler(device, physicalDevLimits, &imageSampler);

    Print("Load Texture end.");
}

void CTexture::destroy(VkDevice device) {
    vkDestroySampler(device, imageSampler, VK_ALLOC);
    vkDestroyImageView(device, imageView, VK_ALLOC);
    vkDestroyImage(device, textureImage, VK_ALLOC);
    vkFreeMemory(device, textureImageMemory, VK_ALLOC);
}
